#include "StdAfx.hpp"
#include "Parser.hpp"
#include "Data.hpp"
#include "CharReader2.hpp"
#include "Tokenizer2.hpp"


ExpressionPtr ParseExpressionAssign(Tokenizer2 &tok);
StatementPtr ParseInlineStatement(Tokenizer2 &tok);
ExpressionPtr ParseExpression10(Tokenizer2 &tok);
StatementPtr ParseStatement0(Tokenizer2 &tok);

bool TryParseTypeName(Tokenizer2 &tok, Type &out)
{
	if (tok.QueryToken(Tokenizer2::TOKEN_IDENTIFIER))
	{
		// Standard type names
		for (uint i = 0; i < Type::TYPE_COUNT; i++)
		{
			if (tok.GetString() == Type::TYPE_NAMES[i])
			{
				out.Set((Type::TYPE)i);
				tok.Next();
				return true;
			}
		}
		// Aliases
		if (tok.GetString() == "uint")
		{
			out.Set(Type::TYPE_UINT32);
			tok.Next();
			return true;
		}
		if (tok.GetString() == "int")
		{
			out.Set(Type::TYPE_INT32);
			tok.Next();
			return true;
		}
	}
	return false;
}

ExpressionPtr ParseExpressionItem(Tokenizer2 &tok)
{
	ExpressionPtr result;

	if (tok.QueryToken(Tokenizer2::TOKEN_INTEGER))
	{
		result.reset(new ExplicitNumericCodeConstant(tok.GetString(), false));
		tok.Next();
	}
	else if (tok.QueryToken(Tokenizer2::TOKEN_FLOAT))
	{
		result.reset(new ExplicitNumericCodeConstant(tok.GetString(), true));
		tok.Next();
	}
	else if (tok.QueryToken(Tokenizer2::TOKEN_CHAR))
	{
		assert(tok.GetString().length() == 1);
		ValuePtr valPtr(new Value(Type(Type::TYPE_CHAR)));
		*(char*)valPtr->GetAddr() = tok.GetString()[0];
		tok.Next();
		result.reset(new Constant(valPtr, true));
	}
	else if (tok.QueryToken(Tokenizer2::TOKEN_STRING))
	{
		ValuePtr valPtr(new Value(Type(Type::TYPE_STRING)));
		*(string*)valPtr->GetAddr() = tok.GetString();
		tok.Next();
		result.reset(new Constant(valPtr, true));
	}
	else if (tok.QueryIdentifier("false"))
	{
		tok.Next();
		ValuePtr valPtr(new Value(Type(Type::TYPE_BOOL)));
		*(bool*)valPtr->GetAddr() = false;
		result.reset(new Constant(valPtr, true));
	}
	else if (tok.QueryIdentifier("true"))
	{
		tok.Next();
		ValuePtr valPtr(new Value(Type(Type::TYPE_BOOL)));
		*(bool*)valPtr->GetAddr() = true;
		result.reset(new Constant(valPtr, true));
	}
	else if (tok.QuerySymbol('('))
	{
		tok.Next();
		result.reset(ParseExpressionA(tok));
		tok.AssertSymbol(')');
		tok.Next();
	}
	else if (tok.QueryToken(Tokenizer2::TOKEN_IDENTIFIER))
	{
		result.reset(new IdentifierExpression(tok.GetString()));
		tok.Next();
	}
	else
		tok.CreateError("Expression expected");

	for (;;)
	{
		// Postincrementation
		if (tok.QuerySymbol("++"))
		{
			tok.Next();
			result.reset(new UnaryOperator(UnaryOperator::OP_INC_POST, result));
		}
		// Postdecrementation
		else if (tok.QuerySymbol("--"))
		{
			tok.Next();
			result.reset(new UnaryOperator(UnaryOperator::OP_DEC_POST, result));
		}
		// Member access
		else if (tok.QuerySymbol('.'))
		{
			tok.Next();
			tok.AssertToken(Tokenizer2::TOKEN_IDENTIFIER);
			result.reset(new MemberOperator(result, tok.GetString()));
			tok.Next();
		}
		// Function call
		else if (tok.QuerySymbol('('))
		{
			tok.Next();
			FunctionCall *callExpr = new FunctionCall(result);
			result.reset(callExpr);

			if (!tok.QuerySymbol(')'))
			{
				callExpr->Params.push_back(ExpressionPtr(ParseExpressionAssign(tok)));
				while (!tok.QuerySymbol(')'))
				{
					tok.AssertSymbol(',');
					tok.Next();
					callExpr->Params.push_back(ExpressionPtr(ParseExpressionAssign(tok)));
				}
			}
			tok.Next(); // ')'
		}
		// Function call
		else if (tok.QuerySymbol('['))
		{
			tok.Next();
			IndexExpression *indexExpr = new IndexExpression(result);
			result.reset(indexExpr);

			if (!tok.QuerySymbol(']'))
			{
				indexExpr->IndexExpr.push_back(ExpressionPtr(ParseExpressionAssign(tok)));
				while (!tok.QuerySymbol(']'))
				{
					tok.AssertSymbol(',');
					tok.Next();
					indexExpr->IndexExpr.push_back(ExpressionPtr(ParseExpressionAssign(tok)));
				}
			}
			tok.Next(); // ']'
		}
		else
			break;
	}

	return result;
}

ExpressionPtr ParseSizeofExpression(Tokenizer2 &tok)
{
	tok.AssertIdentifier("sizeof");
	tok.Next();
	
	Tokenizer2::Iterator it = tok.GetIterator();
	if (tok.QuerySymbol('('))
	{
		tok.Next();
		Type type;
		if (TryParseTypeName(tok, type))
		{
			tok.AssertSymbol(')');
			tok.Next();
			if (!type.CheckClass(Type::CLASS_PHYSICAL))
				throw Error("Cannot use sizeof operator for expression of type " + type.GetName_r());

			ValuePtr valPtr(new Value(Type(Type::TYPE_UINT32)));
			*(uint*)valPtr->GetAddr() = type.GetSize();
			return ExpressionPtr(new Constant(valPtr, false));
		}
	}
	tok.SetIterator(it);
	return ExpressionPtr(new UnaryOperator(UnaryOperator::OP_SIZEOF, ParseExpression10(tok)));
}

ExpressionPtr ParseExpression10(Tokenizer2 &tok)
{
	if (tok.QuerySymbol('+'))
	{
		tok.Next();
		return ParseExpression10(tok);
	}
	if (tok.QuerySymbol('-'))
	{
		tok.Next();
		return ExpressionPtr(new UnaryOperator(UnaryOperator::OP_NUM_NEGATION, ParseExpression10(tok)));
	}
	if (tok.QuerySymbol('~'))
	{
		tok.Next();
		return ExpressionPtr(new UnaryOperator(UnaryOperator::OP_BIN_NEGATION, ParseExpression10(tok)));
	}
	if (tok.QuerySymbol('!'))
	{
		tok.Next();
		return ExpressionPtr(new UnaryOperator(UnaryOperator::OP_LOG_NEGATION, ParseExpression10(tok)));
	}
	if (tok.QuerySymbol("++"))
	{
		tok.Next();
		return ExpressionPtr(new UnaryOperator(UnaryOperator::OP_INC_PRE, ParseExpression10(tok)));
	}
	if (tok.QuerySymbol("--"))
	{
		tok.Next();
		return ExpressionPtr(new UnaryOperator(UnaryOperator::OP_DEC_PRE, ParseExpression10(tok)));
	}
	if (tok.QueryIdentifier("sizeof"))
		return ParseSizeofExpression(tok);
	// Type cast: ( type ) expr
	if (tok.QuerySymbol('('))
	{
		Tokenizer2::Iterator it = tok.GetIterator();
		tok.Next();
		Type castType;
		if (TryParseTypeName(tok, castType))
		{
			tok.AssertSymbol(')');
			tok.Next();
			return ExpressionPtr(new TypeConversion(ParseExpression10(tok), castType, true));
		}
		// else go further, to ParseExpressionItem.
		tok.SetIterator(it);
	}
	
	return ParseExpressionItem(tok);
}

ExpressionPtr ParseExpression9(Tokenizer2 &tok)
{
	ExpressionPtr result = ParseExpression10(tok);

	for (;;)
	{
		if (tok.QuerySymbol('*'))
		{
			tok.Next();
			result.reset(new BinaryOperator(BinaryOperator::OP_NUM_MULTIPLICATION, result, ParseExpression10(tok)));
		}
		else if (tok.QuerySymbol('/'))
		{
			tok.Next();
			result.reset(new BinaryOperator(BinaryOperator::OP_NUM_DIVISION, result, ParseExpression10(tok)));
		}
		else if (tok.QuerySymbol('%'))
		{
			tok.Next();
			result.reset(new BinaryOperator(BinaryOperator::OP_NUM_MODULO, result, ParseExpression10(tok)));
		}
		else
			return result;
	}
}

ExpressionPtr ParseExpression8(Tokenizer2 &tok)
{
	ExpressionPtr result = ParseExpression9(tok);

	for (;;)
	{
		if (tok.QuerySymbol('+'))
		{
			tok.Next();
			result.reset(new BinaryOperator(BinaryOperator::OP_NUM_ADDITION, result, ParseExpression9(tok)));
		}
		else if (tok.QuerySymbol('-'))
		{
			tok.Next();
			result.reset(new BinaryOperator(BinaryOperator::OP_NUM_SUBTRACTION, result, ParseExpression9(tok)));
		}
		else
			return result;
	}
}

ExpressionPtr ParseExpression7(Tokenizer2 &tok)
{
	ExpressionPtr result = ParseExpression8(tok);

	for (;;)
	{
		if (tok.QuerySymbol("<<"))
		{
			tok.Next();
			result.reset(new BinaryOperator(BinaryOperator::OP_BIN_SHIFT_LEFT, result, ParseExpression8(tok)));
		}
		else if (tok.QuerySymbol(">>"))
		{
			tok.Next();
			result.reset(new BinaryOperator(BinaryOperator::OP_BIN_SHIFT_RIGHT, result, ParseExpression8(tok)));
		}
		else
			return result;
	}
}

ExpressionPtr ParseExpression6(Tokenizer2 &tok)
{
	ExpressionPtr result = ParseExpression7(tok);

	for (;;)
	{
		if (tok.QuerySymbol('<'))
		{
			tok.Next();
			result.reset(new BinaryOperator(BinaryOperator::OP_CMP_LESS, result, ParseExpression7(tok)));
		}
		else if (tok.QuerySymbol('>'))
		{
			tok.Next();
			result.reset(new BinaryOperator(BinaryOperator::OP_CMP_GREATER, result, ParseExpression7(tok)));
		}
		else if (tok.QuerySymbol("<="))
		{
			tok.Next();
			result.reset(new BinaryOperator(BinaryOperator::OP_CMP_LESS_EQUAL, result, ParseExpression7(tok)));
		}
		else if (tok.QuerySymbol(">="))
		{
			tok.Next();
			result.reset(new BinaryOperator(BinaryOperator::OP_CMP_GREATER_EQUAL, result, ParseExpression7(tok)));
		}
		else
			return result;
	}
}

ExpressionPtr ParseExpression5(Tokenizer2 &tok)
{
	ExpressionPtr result = ParseExpression6(tok);

	for (;;)
	{
		if (tok.QuerySymbol("=="))
		{
			tok.Next();
			result.reset(new BinaryOperator(BinaryOperator::OP_CMP_EQUAL, result, ParseExpression6(tok)));
		}
		else if (tok.QuerySymbol("!="))
		{
			tok.Next();
			result.reset(new BinaryOperator(BinaryOperator::OP_CMP_NOT_EQUAL, result, ParseExpression6(tok)));
		}
		else
			return result;
	}
}

ExpressionPtr ParseExpression4(Tokenizer2 &tok)
{
	ExpressionPtr result = ParseExpression5(tok);

	for (;;)
	{
		if (tok.QuerySymbol('&'))
		{
			tok.Next();
			result.reset(new BinaryOperator(BinaryOperator::OP_BIN_AND, result, ParseExpression5(tok)));
		}
		else
			return result;
	}
}

ExpressionPtr ParseExpression3(Tokenizer2 &tok)
{
	ExpressionPtr result = ParseExpression4(tok);

	for (;;)
	{
		if (tok.QuerySymbol('^'))
		{
			tok.Next();
			result.reset(new BinaryOperator(BinaryOperator::OP_BIN_XOR, result, ParseExpression4(tok)));
		}
		else
			return result;
	}
}

ExpressionPtr ParseExpression2(Tokenizer2 &tok)
{
	ExpressionPtr result = ParseExpression3(tok);

	for (;;)
	{
		if (tok.QuerySymbol('|'))
		{
			tok.Next();
			result.reset(new BinaryOperator(BinaryOperator::OP_BIN_OR, result, ParseExpression3(tok)));
		}
		else
			return result;
	}
}

ExpressionPtr ParseExpression1(Tokenizer2 &tok)
{
	ExpressionPtr result = ParseExpression2(tok);

	for (;;)
	{
		if (tok.QuerySymbol("&&"))
		{
			tok.Next();
			result.reset(new BinaryOperator(BinaryOperator::OP_LOG_AND, result, ParseExpression2(tok)));
		}
		else
			return result;
	}
}

ExpressionPtr ParseExpression0(Tokenizer2 &tok)
{
	ExpressionPtr result = ParseExpression1(tok);

	for (;;)
	{
		if (tok.QuerySymbol("||"))
		{
			tok.Next();
			result.reset(new BinaryOperator(BinaryOperator::OP_LOG_OR, result, ParseExpression1(tok)));
		}
		else
			return result;
	}
}

ExpressionPtr ParseExpressionAa(Tokenizer2 &tok)
{
	ExpressionPtr expr0 = ParseExpression0(tok);

	if (tok.QuerySymbol('?'))
	{
		tok.Next();
		ExpressionPtr trueExpr = ParseExpression0(tok);
		tok.AssertSymbol(':');
		tok.Next();
		return ExpressionPtr(new ConditionalOperator(expr0, trueExpr, ParseExpressionAa(tok)));
	}
	else
		return expr0;
}

ExpressionPtr ParseExpressionAssign(Tokenizer2 &tok)
{
	ExpressionPtr expr0 = ParseExpressionAa(tok);
	if (tok.QueryToken(Tokenizer2::TOKEN_SYMBOL) && BinaryOperator::SymbolIsAssignmentOperator(tok.GetString()))
	{
		BinaryOperator::OP_TYPE opType = BinaryOperator::SymbolToOpType(tok.GetString());
		assert(opType != BinaryOperator::OP_TYPE_COUNT);
		tok.Next();
		return ExpressionPtr(new BinaryOperator(opType, expr0, ParseExpressionAssign(tok)));
	}
	else
		return expr0;
}

ExpressionPtr ParseExpressionA(Tokenizer2 &tok)
{
	ExpressionPtr result = ParseExpressionAssign(tok);

	for (;;)
	{
		if (tok.QuerySymbol(','))
		{
			tok.Next();
			result.reset(new BinaryOperator(BinaryOperator::OP_RETURN_LEFT, result, ParseExpressionAssign(tok)));
		}
		else
			return result;
	}
}

void ParseStatementCollection(Tokenizer2 &tok, StatementCollection &statementCollection)
{
	while (!tok.QueryToken(Tokenizer2::TOKEN_EOF)
		&& !tok.QuerySymbol('}')
		&& !tok.QueryIdentifier("case")
		&& !tok.QueryIdentifier("default"))
	{
		statementCollection.SubStatements.push_back(ParseStatement0(tok));
	}
}

StatementPtr ParseStatementBlock(Tokenizer2 &tok)
{
	BlockStatement *blockStatement = new BlockStatement();
	StatementPtr sptr(blockStatement);
	ParseStatementCollection(tok, *blockStatement);
	return sptr;
}

StatementPtr ParseIfStatement(Tokenizer2 &tok)
{
	tok.AssertIdentifier("if");
	tok.Next();

	tok.AssertSymbol('(');
	tok.Next();

	ExpressionPtr condExpr(ParseExpressionA(tok));

	tok.AssertSymbol(')');
	tok.Next();

	StatementPtr trueStatement(ParseStatement0(tok));

	if (tok.QueryIdentifier("else"))
	{
		tok.Next();

		StatementPtr falseStatement(ParseStatement0(tok));
		return StatementPtr(new IfStatement(condExpr, trueStatement, falseStatement));
	}
	else
		return StatementPtr(new IfStatement(condExpr, trueStatement, StatementPtr()));
}

StatementPtr ParseWhileStatement(Tokenizer2 &tok)
{
	tok.AssertIdentifier("while");
	tok.Next();

	tok.AssertSymbol('(');
	tok.Next();

	ExpressionPtr condExpr(ParseExpressionA(tok));

	tok.AssertSymbol(')');
	tok.Next();

	return StatementPtr(new WhileStatement(condExpr, ParseStatement0(tok)));
}

StatementPtr ParseDoWhileStatement(Tokenizer2 &tok)
{
	tok.AssertIdentifier("do");
	tok.Next();

	StatementPtr subStatement(ParseStatement0(tok));

	tok.AssertIdentifier("while");
	tok.Next();

	tok.AssertSymbol('(');
	tok.Next();

	ExpressionPtr condExpr(ParseExpressionA(tok));

	tok.AssertSymbol(')');
	tok.Next();

	tok.AssertSymbol(';');
	tok.Next();

	return StatementPtr(new DoWhileStatement(condExpr, subStatement));
}

StatementPtr ParseForStatement(Tokenizer2 &tok)
{
	tok.AssertIdentifier("for");
	tok.Next();

	tok.AssertSymbol('(');
	tok.Next();

	StatementPtr initStatement;
	if (!tok.QuerySymbol(';'))
	{
		initStatement.reset(ParseInlineStatement(tok));
		tok.AssertSymbol(';');
	}
	tok.Next(); // Skip symbol (;)

	ExpressionPtr condExpr;
	if (!tok.QuerySymbol(';'))
	{
		condExpr.reset(ParseExpressionA(tok));
		tok.AssertSymbol(';');
	}
	tok.Next(); // Skip symbol (;)

	ExpressionPtr postExpr;
	if (!tok.QuerySymbol(')'))
	{
		postExpr.reset(ParseExpressionA(tok));
		tok.AssertSymbol(')');
	}
	tok.Next(); // Skip symbol ')'

	return StatementPtr(new ForStatement(initStatement, condExpr, postExpr, ParseStatement0(tok)));
}

// Type is already parsed and given as parameter.
void ParseVariableDef(VariableDefVector &outDefs, Tokenizer2 &tok, const Type &type)
{
	outDefs.clear();

	string name;
	ExpressionPtr initialExpr;
	for (;;)
	{
		// Variable name
		tok.AssertToken(Tokenizer2::TOKEN_IDENTIFIER);
		name = tok.GetString();
		tok.Next();
		// Initialization expression
		if (tok.QuerySymbol('='))
		{
			tok.Next();
			initialExpr.reset(ParseExpressionAssign(tok));
		}
		// No initialization
		else
			initialExpr.reset();

		outDefs.push_back(VariableDefPtr(new VariableDef(type, name, initialExpr)));

		if (tok.QuerySymbol(','))
			tok.Next();
		else
			return;
	}
}

StatementPtr ParseInlineStatement(Tokenizer2 &tok)
{
	Type varType;
	if (TryParseTypeName(tok, varType))
	{
		VariableDefinitionStatement *varDefStatement = new VariableDefinitionStatement();
		StatementPtr result(varDefStatement);
		ParseVariableDef(varDefStatement->VariableDefs, tok, varType);
		return result;
	}
	else
		return StatementPtr(new ExpressionStatement(ParseExpressionA(tok)));
}

StatementPtr ParseSwitchStatement(Tokenizer2 &tok)
{
	tok.AssertIdentifier("switch");
	tok.Next();

	tok.AssertSymbol('(');
	tok.Next();

	ExpressionPtr valExpr(ParseExpressionA(tok));

	tok.AssertSymbol(')');
	tok.Next();

	tok.AssertSymbol('{');
	tok.Next();

	SwitchStatement *switchStatement = new SwitchStatement(valExpr);
	StatementPtr result(switchStatement);

	while (tok.QueryIdentifier("case"))
	{
		tok.Next();

		std::vector<ExpressionPtr> exprs;
		exprs.push_back(ExpressionPtr(ParseExpressionAssign(tok)));

		while (tok.QuerySymbol(','))
		{
			tok.Next();
			exprs.push_back(ExpressionPtr(ParseExpressionAssign(tok)));
		}

		tok.AssertSymbol(':');
		tok.Next();

		StatementPtr statementBlock(ParseStatementBlock(tok));

		for (uint i = 0; i < exprs.size()-1; i++)
		{
			switchStatement->ValueExprs.push_back(exprs[i]);
			switchStatement->SubStatements.push_back(StatementPtr());
		}
		switchStatement->ValueExprs.push_back(exprs.back());
		switchStatement->SubStatements.push_back(statementBlock);
	}

	if (tok.QueryIdentifier("default"))
	{
		tok.Next();

		tok.AssertSymbol(':');
		tok.Next();

		switchStatement->DefaultStatement.reset(ParseStatementBlock(tok));
	}

	tok.AssertSymbol('}');
	tok.Next();

	return result;
}

StatementPtr ParseReturnStatement(Tokenizer2 &tok)
{
	tok.AssertIdentifier("return");
	tok.Next();

	ExpressionPtr resultExpr;
	if (!tok.QuerySymbol(';'))
		resultExpr = ParseExpressionA(tok);

	tok.AssertSymbol(';');
	tok.Next();

	return StatementPtr(new ReturnStatement(resultExpr));
}

StatementPtr ParseStatement0(Tokenizer2 &tok)
{
	StatementPtr sptr;

	// Empty statement: ;
	if (tok.QuerySymbol(';'))
	{
		tok.Next();
		sptr.reset(new EmptyStatement());
	}
	// Statement block: { ... }
	else if (tok.QuerySymbol('{'))
	{
		tok.Next();

		sptr = ParseStatementBlock(tok);

		tok.AssertSymbol('}');
		tok.Next();
	}
	// if (...) ... else ...
	else if (tok.QueryIdentifier("if"))
		sptr.reset(ParseIfStatement(tok));
	// while loop
	else if (tok.QueryIdentifier("while"))
		sptr.reset(ParseWhileStatement(tok));
	// do-while loop
	else if (tok.QueryIdentifier("do"))
		sptr.reset(ParseDoWhileStatement(tok));
	// for loop
	else if (tok.QueryIdentifier("for"))
		sptr.reset(ParseForStatement(tok));
	// switch
	else if (tok.QueryIdentifier("switch"))
		sptr.reset(ParseSwitchStatement(tok));
	else if (tok.QueryIdentifier("break"))
	{
		tok.Next();
		tok.AssertSymbol(';');
		tok.Next();
		sptr.reset(new BreakStatement());
	}
	else if (tok.QueryIdentifier("continue"))
	{
		tok.Next();
		tok.AssertSymbol(';');
		tok.Next();
		sptr.reset(new ContinueStatement());
	}
	else if (tok.QueryIdentifier("return"))
		sptr.reset(ParseReturnStatement(tok));
	else
	{
		sptr.reset(ParseInlineStatement(tok));
		tok.AssertSymbol(';');
		tok.Next();
	}

	return sptr;
}

shared_ptr<FunctionParamDef> ParseFunctionParamDef(Tokenizer2 &tok)
{
	// Type
	Type type;
	if (!TryParseTypeName(tok, type))
		throw Error("Type expected");

	// Name
	string name;
	if (tok.QueryToken(Tokenizer2::TOKEN_IDENTIFIER))
	{
		name = tok.GetString();
		tok.Next();
	}

	// Initialization
	ExpressionPtr initExpr;
	if (tok.QuerySymbol('='))
	{
		tok.Next();
		initExpr.reset(ParseExpressionAssign(tok));
	}

	return shared_ptr<FunctionParamDef>(new FunctionParamDef(type, name, initExpr));
}

ModuleElementPtr ParseModuleElement(Tokenizer2 &tok)
{
	// Function def or global var def, here must be type followed by name anyway.

	Type type;
	if (!TryParseTypeName(tok, type))
		throw Error("Type expected");

	Tokenizer2::Iterator it = tok.GetIterator();

	tok.AssertToken(Tokenizer2::TOKEN_IDENTIFIER);
	string name = tok.GetString();
	tok.Next();

	// Function definition
	if (tok.QuerySymbol('('))
	{
		tok.Next();
		FunctionDef *functionDef = new FunctionDef(type, name);
		ModuleElementPtr result(functionDef);
		if (!tok.QuerySymbol(')'))
		{
			functionDef->ParamDefs.push_back(ParseFunctionParamDef(tok));
			while (!tok.QuerySymbol(')'))
			{
				tok.AssertSymbol(',');
				tok.Next();
				functionDef->ParamDefs.push_back(ParseFunctionParamDef(tok));
			}
		}
		tok.Next(); // Symbol ')'

		tok.AssertSymbol('{');
		tok.Next();

		ParseStatementCollection(tok, *functionDef);

		tok.AssertSymbol('}');
		tok.Next();
		
		return result;
	}
	// Global variables definition
	else
	{
		tok.SetIterator(it);
		GlobalVariableDef *varDef = new GlobalVariableDef();
		ModuleElementPtr result(varDef);
		ParseVariableDef(varDef->VariableDefs, tok, type);
		return result;
	}
}

ModulePtr ParseModule( Tokenizer2 &tok )
{
	shared_ptr<Module> module(new Module());

	while (!tok.QueryToken(Tokenizer2::TOKEN_EOF))
	{
		// Empty element
		if (tok.QuerySymbol(';'))
			tok.Next();
		// Meaningful element
		else
			module->Elements.push_back(ModuleElementPtr(ParseModuleElement(tok)));
	}

	return module;
}

CodeBlockPtr ParseCodeBlock( Tokenizer2 &tok )
{
	CodeBlock *block = new CodeBlock();
	CodeBlockPtr result(block);
	ParseStatementCollection(tok, *block);
	return result;
}
